LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-05-2013, 11:42 AM   #1
hashbang#!
Member
 
Registered: Aug 2009
Location: soon to be independent Scotland
Distribution: Debian
Posts: 120

Rep: Reputation: 17
[bash] dynamic variables - assign value containing spaces


I have a lot of repetitive code here and I tried to replace this piece of code with dynamic variables using eval:

Code:
[[ ! -z "$bg" ]] && bg_canvas=$(canvas $bg_colour)
[[ ! -z "$fg" ]] && fg_canvas=$(canvas $fg_colour)
...
I would like to achieve something like this:

Code:
for t in fg bg; do 
    eval [[ ! -z "'$'${t}" ]] && ${t}_canvas=$(canvas '$'${t}_colour)
done
I ran into two problems:
  1. I didn't know how to test the value of dynamic variable '$'${t}
  2. The output of $(canvas $fg_colour) contains spaces, e.g. "#ff0 #00a", which leads to error bash: #00a: command not found

Any help would be very much appreciated.
 
Old 01-05-2013, 12:19 PM   #2
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192
Generally there are very few reasons to use dynamic variable names. My suggestion would be to use associative arrays using the appropriate names, bg & fg, and test and set as needed.
This will also negate the issue you are having with spaces as you simply quote the whole variable.

And of course the use of eval should always be kept to a minimum or avoided where possible.
 
Old 01-05-2013, 05:32 PM   #3
hashbang#!
Member
 
Registered: Aug 2009
Location: soon to be independent Scotland
Distribution: Debian
Posts: 120

Original Poster
Rep: Reputation: 17
Thank you for your response, grail.

On this occasion I would find it more convenient to use dynamic variables as I have already used this technique elsewhere in the script.

My main stumbling block is 2) - assigning values with spaces to dynamic variables. Is there any way round the problem?
For 1) I have a work-around.
 
Old 01-06-2013, 12:23 AM   #4
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192
Quote:
On this occasion I would find it more convenient to use dynamic variables as I have already used this technique elsewhere in the script.
As the old saying goes, continuing with a bad idea because you started with it is hardly a reason to continue.

That being said, the only way I know of nullifying the space issue is either:

1. use double quotes where necessary

2. assuming the above does not work, replace all spaces with something like an underscore and then reverse the process when needing the space version

Generally the idea for me would be, if you need to use option 2 then the overhead associated would mean you need to rethink the design choice.

If David H sees this thread he may have other ideas.
 
Old 01-06-2013, 06:14 AM   #5
millgates
Member
 
Registered: Feb 2009
Location: 192.168.x.x
Distribution: Slackware
Posts: 852

Rep: Reputation: 389Reputation: 389Reputation: 389Reputation: 389
First of all, don't use eval.
Also, and I can't stress this enough, you shouldn't use eval.
Last, but not least, DON'T USE EVAL!

This is exactly what the associative arrays are for:

Code:
#!/bin/bash

declare -A array
array[bg_color]="foo  bar"
array[fg_color]="baz"

for i in bg fg; do
    echo "i: ${array["${i}_color"]}"
done
Another way of indirection, if you really don't want to use arrays:
Code:
#!/bin/bash

bg_color="foo  bar"
fg_color=baz
for i in bg fg; do
    var="${i}_color"
    echo "$var: ${!var}"
done
If you really really really can't sleep well without using eval, (did I mention you shouldn't?), you have to quote what you don't want to be word-split. Eval will make the line be processed twice, so you may need to use two layers of quotes or escape them:

Code:
#!/bin/bash

bg_color="foo  bar"
fg_color=baz
for i in bg fg; do
    eval echo "$i: \"\$${i}_color\""
done
 
1 members found this post helpful.
Old 01-06-2013, 12:51 PM   #6
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,780

Rep: Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212
Post

Quote:
Originally Posted by hashbang#! View Post
I would like to achieve something like this:

Code:
for t in fg bg; do 
    eval [[ ! -z "'$'${t}" ]] && ${t}_canvas=$(canvas '$'${t}_colour)
done
This should work, using an intermediate variable for the parameter name, '!' for indirection, and "declare" to allow expansion of the LHS of the assignment:
Code:
for T in fg bg; do
    Param=${t}_colour
    [[ ! -z "${!t}" ]] && declare ${t}_canvas="$(canvas ${!Param})"
done
 
2 members found this post helpful.
Old 01-06-2013, 01:01 PM   #7
hashbang#!
Member
 
Registered: Aug 2009
Location: soon to be independent Scotland
Distribution: Debian
Posts: 120

Original Poster
Rep: Reputation: 17
Quote:
Originally Posted by millgates View Post
First of all, don't use eval.
Also, and I can't stress this enough, you shouldn't use eval.
Last, but not least, DON'T USE EVAL!
You made me smile on this miserable rainy Sunday.
But neither of you mentioned what's so evil about eval.

Quote:
Originally Posted by millgates View Post
Another way of indirection, if you really don't want to use arrays:
[...]
I like the ${!var} style indirection a lot but it doesn't seem to be possible to assign a value to a dynamically referenced variable:
Code:
${!var}=blue

Last edited by hashbang#!; 01-06-2013 at 01:20 PM.
 
Old 01-06-2013, 01:07 PM   #8
hashbang#!
Member
 
Registered: Aug 2009
Location: soon to be independent Scotland
Distribution: Debian
Posts: 120

Original Poster
Rep: Reputation: 17
rknichols, our posts crossed. I am in the process of testing your suggestion.
 
Old 01-06-2013, 01:19 PM   #9
hashbang#!
Member
 
Registered: Aug 2009
Location: soon to be independent Scotland
Distribution: Debian
Posts: 120

Original Poster
Rep: Reputation: 17
Quote:
Originally Posted by rknichols View Post
This should work, using an intermediate variable for the parameter name, '!' for indirection, and "declare" to allow expansion of the LHS of the assignment:
Code:
for T in fg bg; do
    Param=${t}_colour
    [[ ! -z "${!t}" ]] && declare ${t}_canvas="$(canvas ${!Param})"
done
That is ingenious!
 
Old 01-06-2013, 02:34 PM   #10
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
Just an aside note: instead of
Code:
! -z
you can use
Code:
-n
which is the same but more concise.
 
1 members found this post helpful.
Old 01-06-2013, 02:37 PM   #11
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
Quote:
Originally Posted by hashbang#! View Post
But neither of you mentioned what's so evil about eval.
Here is a useful link: http://mywiki.wooledge.org/BashFAQ/048 and here another article about associative arrays and indirect reference: http://mywiki.wooledge.org/BashFAQ/006.
 
1 members found this post helpful.
Old 01-06-2013, 04:13 PM   #12
hashbang#!
Member
 
Registered: Aug 2009
Location: soon to be independent Scotland
Distribution: Debian
Posts: 120

Original Poster
Rep: Reputation: 17
colucix - thanks for the useful links
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] (BASH) How to assign 2 variables to same line? Dick Dastardly Programming 10 01-15-2012 09:17 AM
[SOLVED] [Bash] Dynamic variables ? czezz Programming 3 04-29-2011 05:32 AM
dynamic variables and heredocuments in bash xeon123 Linux - Newbie 1 04-04-2011 10:20 AM
[SOLVED] Bash gurus: Using 'cut' to assign multiple shell variables? forbin Programming 9 08-08-2010 11:15 AM
moving files that have spaces in variables -bash scripting bhar0761 Programming 10 09-22-2005 07:30 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:36 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration